#include "U2GLESDefaultHardwareBufferManager.h"

#include "U2Exception.h"


U2EG_NAMESPACE_USING


U2GLESDefaultHardwareVertexBuffer::U2GLESDefaultHardwareVertexBuffer(size_t vertexSize,
                                                             size_t numVertices,
                                                             U2HardwareBuffer::Usage usage)
    : U2HardwareVertexBuffer(0, vertexSize, numVertices, usage, true, false)
{
    mpData = static_cast<unsigned char*>(U2_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
}

U2GLESDefaultHardwareVertexBuffer::U2GLESDefaultHardwareVertexBuffer(U2HardwareBufferManagerBase* mgr,
                                                                 size_t vertexSize,
                                                                 size_t numVertices,
                                                                 U2HardwareBuffer::Usage usage)
: U2HardwareVertexBuffer(mgr, vertexSize, numVertices, usage, true, false)
{
    mpData = static_cast<unsigned char*>(U2_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
}

U2GLESDefaultHardwareVertexBuffer::~U2GLESDefaultHardwareVertexBuffer()
{
    U2_FREE_SIMD(mpData, MEMCATEGORY_GEOMETRY);
}

void* U2GLESDefaultHardwareVertexBuffer::lockImpl(size_t offset,
                                              size_t length,
                                              LockOptions options)
{
    return mpData + offset;
}

void U2GLESDefaultHardwareVertexBuffer::unlockImpl(void)
{
    // Nothing to do
}

void* U2GLESDefaultHardwareVertexBuffer::lock(size_t offset,
                                          size_t length,
                                          LockOptions options)
{
    mIsLocked = true;
    return mpData + offset;
}

void U2GLESDefaultHardwareVertexBuffer::unlock(void)
{
    mIsLocked = false;
    // Nothing to do
}

void U2GLESDefaultHardwareVertexBuffer::readData(size_t offset,
                                             size_t length,
                                             void* pDest)
{
    assert((offset + length) <= mSizeInBytes);
    memcpy(pDest, mpData + offset, length);
}

void U2GLESDefaultHardwareVertexBuffer::writeData(size_t offset,
                                              size_t length,
                                              const void* pSource,
                                              bool discardWholeBuffer)
{
    assert((offset + length) <= mSizeInBytes);
    // ignore discard, memory is not guaranteed to be zeroised
    memcpy(mpData + offset, pSource, length);
}

U2GLESDefaultHardwareIndexBuffer::U2GLESDefaultHardwareIndexBuffer(IndexType idxType,
                                                           size_t numIndexes,
                                                           U2HardwareBuffer::Usage usage)
    : U2HardwareIndexBuffer(0, idxType, numIndexes, usage, true, false)
      // always software, never shadowed
{
	if (idxType == U2HardwareIndexBuffer::IT_32BIT)
	{
		U2_EXCEPT(U2Exception::ERR_INTERNAL_ERROR,
			"32 bit hardware buffers are not allowed in OpenGL ES.",
			"GLESDefaultHardwareIndexBuffer");
	}
    mpData = new unsigned char[mSizeInBytes];
}

U2GLESDefaultHardwareIndexBuffer::~U2GLESDefaultHardwareIndexBuffer()
{
    delete [] mpData;
}

void* U2GLESDefaultHardwareIndexBuffer::lockImpl(size_t offset, size_t length, LockOptions options)
{
    // Only for use internally, no 'locking' as such
    return mpData + offset;
}

void U2GLESDefaultHardwareIndexBuffer::unlockImpl(void)
{
    // Nothing to do
}

void* U2GLESDefaultHardwareIndexBuffer::lock(size_t offset, size_t length, LockOptions options)
{
    mIsLocked = true;
    return mpData + offset;
}

void U2GLESDefaultHardwareIndexBuffer::unlock(void)
{
    mIsLocked = false;
    // Nothing to do
}

void U2GLESDefaultHardwareIndexBuffer::readData(size_t offset, size_t length, void* pDest)
{
    assert((offset + length) <= mSizeInBytes);
    memcpy(pDest, mpData + offset, length);
}

void U2GLESDefaultHardwareIndexBuffer::writeData(size_t offset, size_t length, const void* pSource,
        bool discardWholeBuffer)
{
    assert((offset + length) <= mSizeInBytes);
    // ignore discard, memory is not guaranteed to be zeroised
    memcpy(mpData + offset, pSource, length);
}

U2GLESDefaultHardwareBufferManagerBase::U2GLESDefaultHardwareBufferManagerBase()
{
}

U2GLESDefaultHardwareBufferManagerBase::~U2GLESDefaultHardwareBufferManagerBase()
{
    destroyAllDeclarations();
    destroyAllBindings();
}

U2HardwareVertexBufferSharedPtr
    U2GLESDefaultHardwareBufferManagerBase::createVertexBuffer(size_t vertexSize,
    size_t numVerts, U2HardwareBuffer::Usage usage, bool useShadowBuffer)
{
    return U2HardwareVertexBufferSharedPtr(
        U2_NEW U2GLESDefaultHardwareVertexBuffer(this, vertexSize, numVerts, usage));
}

U2HardwareIndexBufferSharedPtr
    U2GLESDefaultHardwareBufferManagerBase::createIndexBuffer(U2HardwareIndexBuffer::IndexType itype,
    size_t numIndexes, U2HardwareBuffer::Usage usage, bool useShadowBuffer)
{
    return U2HardwareIndexBufferSharedPtr(
        U2_NEW U2GLESDefaultHardwareIndexBuffer(itype, numIndexes, usage));
}
